///////////////////////////////////////////////////////////////////////////////
//    Copyright (c) 2021 CASTest Corporation Limited. All Rights Reserved    //
///////////////////////////////////////////////////////////////////////////////

#include "STILparser.h"

bool STILparser::is_digit(char ch) {
    return ch <= '9' && ch >= '0' ? true : false;
}

bool STILparser::is_letter(char ch) {
    return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ? true : false;
}

void STILparser::print(vector<string> &type, vector<string> &tokens) {
    ofstream fileout("stil_parsed.txt");
    for (int i = 0; i < type.size(); i++) {
        // cout << "token:" << type[i] << "   <" << tokens[i] << ">" << endl;
        fileout << "token:" << type[i] << "   <" << tokens[i] << ">" << endl;
    }
    fileout.close();
}

//because of ambiguous grammar, we need this special processing.
void STILparser::time_expr(vector<string> &type, vector<string> &tokens) {
    int pos = tokens.size() - 1;
    if (tokens.size() >= 3) {
        if (type[pos - 2] == "QUOTE" && type[pos - 1] == "WFC_SEQ" && type[pos] == "QUOTE") {
            string str = tokens[pos - 2] + tokens[pos - 1] + tokens[pos];
            type[pos - 2] = "TIME_EXPR";
            tokens[pos - 2] = str;
            tokens.erase(tokens.begin() + pos - 1, tokens.end());
            type.erase(type.begin() + pos - 1, type.end());
        }
    }
}

void STILparser::scan(vector<string> &type, vector<string> &tokens, string filename) {
    ifstream fin(filename);
    if (!fin) {
        cout << "file read error!" << endl;
        return;
    }
    char ch;
    ch = fin.get();
    while (true) {
        if (ch == EOF) {
//            cout << "file parser end." << endl;
            break;
        }
        if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ';') {
            ch = fin.get();
            continue;
        }
        //ignore
        if (ch == '/') {
            ch = fin.get();
            if (ch == '/') {
                char str[1024];
                //cout << fin.tellg() <<endl;
                fin.getline(str, 1024);
                //cout << fin.tellg() <<endl;
            }
            continue;
        }

        //ignore annotation.
        if (ch == 'A') {
            string t = "";
            t += ch;
            ifstream tmp(filename);
            int length = fin.tellg();
            tmp.seekg(length, tmp.beg);
            int i = 3;
            while (i > 0 && ch != EOF) {
                ch = tmp.get();
                t += ch;
                i--;
            }
            if (t == "Ann ") {
                ch = tmp.get();
                if (ch == '{') {
                    while (ch != '}' && ch != EOF) {
                        ch = tmp.get();
                    }
                    int length = tmp.tellg();
                    fin.seekg(length, fin.beg);
                    ch = fin.get();
                }
            }
            tmp.close();
        }

        switch (ch) {
            case '+': {
                type.push_back("SUM");
                tokens.push_back("+");
                ch = fin.get();
                break;
            }
            case '=': {
                type.push_back("EQ");
                tokens.push_back("=");
                ch = fin.get();
                break;
            }
            case ';': {
                type.push_back("SEMICOLON");
                tokens.push_back(";");
                ch = fin.get();
                break;
            }
            case ':': {
                type.push_back("COLON");
                tokens.push_back(":");
                ch = fin.get();
                break;
            }
            case '{': {
                type.push_back("L_BRACKET");
                tokens.push_back("{");
                ch = fin.get();
                break;
            }
            case '}': {
                type.push_back("R_BRACKET");
                tokens.push_back("}");
                ch = fin.get();
                break;
            }
            case '(': {
                type.push_back("L_PAR");
                tokens.push_back("(");
                ch = fin.get();
                break;
            }
            case ')': {
                type.push_back("R_PAR");
                tokens.push_back(")");
                ch = fin.get();
                break;
            }
            case '!': {
                type.push_back("EXCLAMATION");
                tokens.push_back("!");
                ch = fin.get();
                break;
            }
            case '\'': {
                ch = fin.get();
                type.push_back("QUOTE");
                tokens.push_back("\'");
                time_expr(type, tokens);
                break;
            }
            default: {
                break;
            }
        }

        string token = "";
        //token INT.
        if (is_digit(ch)) {
            token += ch;
            while (is_digit(ch = fin.get())) {
                token += ch;
            }
            //token FLOAT.
            if (ch == '.') {
                token += ch;
                while (is_digit(ch = fin.get())) {
                    token += ch;
                }
                type.push_back("FLOAT");
                tokens.push_back(token);
                continue;
            }
                //token WFC_SEQ.
            else if (is_letter(ch) || ch == '#' || ch == '%') {
                while (is_digit(ch) || is_letter(ch) || ch == '#' || ch == '%') {
                    token += ch;
                    ch = fin.get();
                }
                type.push_back("WFC_SEQ");
                tokens.push_back(token);
                continue;
            }
            type.push_back("INT");
            tokens.push_back(token);
            continue;
        }
            //token STRING.
        else if (ch == '"') {
            token += ch;
            while (true) {
                ch = fin.get();
                if (ch != '\r' && ch != '\n' && ch != '"') {
                    token += ch;
                    continue;
                } else {
                    break;
                }
            }

            char pred = ch;
            if (ch == '\r' || ch == '\n' || ch == '"') {
                token += ch;
                while (true) {
                    ch = fin.get();
                    if (ch == '\r' || ch == '\n' || ch == '"') {
                        token += ch;
                        pred = ch;
                        continue;
                    }
                    if (pred == '"') {
                        type.push_back("STRING");
                        tokens.push_back(token);
                        break;
                    } else {
                        cout << "error in string!" << endl;
                        return;
                    }
                }
            }
            continue;
        }
            //token CHARS.
        else if (is_letter(ch)) {
            token += ch;
            while (true) {
                ch = fin.get();
                if (is_letter(ch)) {
                    token += ch;
                    continue;
                }
                    //token WFC_SEQ.
                else if (is_digit(ch) || ch == '#' || ch == '%') {
                    while (is_digit(ch) || is_letter(ch) || ch == '#' || ch == '%') {
                        token += ch;
                        ch = fin.get();
                    }
                    type.push_back("WFC_SEQ");
                    tokens.push_back(token);
                    continue;
                }
                    //UNIT.
                else {
                    if (token == "ns" || token == "ms" || token == "s") {
                        type.push_back("UNIT");
                        tokens.push_back(token);
                        break;
                    }
                    type.push_back("CHARS");
                    tokens.push_back(token);
                    break;
                }
            }
            continue;
        } else if (ch == '\\') {
            token += ch;
            ch = fin.get();
            if (ch == 'r') {
                token += ch;
                type.push_back("REPEAT");
                tokens.push_back(token);
                ch = fin.get();
            } else if (ch == 'j') {
                token += ch;
                type.push_back("JOIN");
                tokens.push_back(token);
                ch = fin.get();
            } else {
                cout << "error in symbols" << endl;
                return;
            }
            continue;
        } else if (ch == '#' || ch == '%') {
            while (is_digit(ch) || is_letter(ch) || ch == '#' || ch == '%') {
                token += ch;
                ch = fin.get();
            }
            type.push_back("WFC_SEQ");
            tokens.push_back(token);
            continue;
        }
    }
    fin.close();
    return;
}

void STILparser::err_exit() {
    cout << "error at " << "index: " << i << " token: " << tokens[i] << "  !" << endl;
    exit(-1);
}

void STILparser::pass(const string &t) {
    if (type[i] == t) {
        i++;
    } else {
        err_exit();
    }
}

bool STILparser::float_t() {
    if (type[i] == "FLOAT") {
        pass("FLOAT");
        return true;
    }
    return false;
}

bool STILparser::event_code() {
    if (type[i] == "CHARS") {
        pass("CHARS");
        return true;
    }
    return false;
}

bool STILparser::time_expr() {
    if (type[i] == "TIME_EXPR") {
        pass("TIME_EXPR");
        return true;
    }
    return false;
}

bool STILparser::int_t() {
    if (type[i] == "INT") {
        pass("INT");
        return true;
    }
    return false;
}

bool STILparser::id() {
    if (type[i] == "STRING") {
        pass("STRING");
        return true;
    }
    return false;
}

bool STILparser::wfc_seq() {
    if (type[i] == "CHARS") {
        proc += tokens[i] + " ";
        i++;
        return true;
    } else if (type[i] == "INT") {
        proc += tokens[i] + " ";
        i++;
        return true;
    } else if (type[i] == "WFC_SEQ") {
        proc += tokens[i] + " ";
        i++;
        return true;
    }
    return false;
}

//////////////////////////////////////////////////////////////////
//ASSIGS.
bool STILparser::repeat() {
    if (type[i] == "REPEAT") {
        proc += "repeat ";
        i++;
        proc += tokens[i] + " ";
        if (!int_t()) err_exit();
        if (!wfc_seq()) err_exit();
        return true;
    }
    return false;
}

void STILparser::assig_expr() {
    if (type[i] == "JOIN") {
        proc += tokens[i];
        i++;
    }
    while ((repeat() || wfc_seq()) && i < len);
}

bool STILparser::assig() {
    if (id()) {
        proc += tokens[i - 1] + " ";
        pass("EQ");
        assig_expr();
        return true;
    }
    return false;
}

void STILparser::assigs() {
    while (assig() && i < len);
}

//INST LIST.
bool STILparser::iddq_inst() {
    if (tokens[i] == "IddqTestPoint") {
        i++;
        return true;
    }
    return false;
}

bool STILparser::stop_inst() {
    if (tokens[i] == "Stop") {
        i++;
        return true;
    }
    return false;
}

bool STILparser::macro_inst() {
    if (tokens[i] == "Macro") {
        i++;
        if (!id()) err_exit();
        if (type[i] == "L_BRACKET") {
            pass("L_BRACKET");
            assigs();
            pass("R_BRACKET");
        }
        return true;
    }
    return false;
}

bool STILparser::call_inst() {
    if (tokens[i] == "Call") {
        proc += tokens[i] + " ";
        i++;
        proc += tokens[i] + " ";
        if (!id()) err_exit();
        if (type[i] == "L_BRACKET") {
            pass("L_BRACKET");
            assigs();
            pass("R_BRACKET");
        }
        return true;
    }
    return false;
}

bool STILparser::v_inst() {
    if (tokens[i] == "V") {
        proc += tokens[i] + " ";
        i++;
        pass("L_BRACKET");
        assigs();
        pass("R_BRACKET");
        return true;
    }
    return false;
}

bool STILparser::f_inst() {
    if (tokens[i] == "F") {
        i++;
        pass("L_BRACKET");
        assigs();
        pass("R_BRACKET");
        return true;
    }
    return false;
}

bool STILparser::c_inst() {
    if (tokens[i] == "C") {
        proc += tokens[i] + " ";
        i++;
        pass("L_BRACKET");
        assigs();
        pass("R_BRACKET");
        return true;
    }
    return false;
}

bool STILparser::w_inst() {
    if (tokens[i] == "W") {
        i++;
        if (!id()) err_exit();
        return true;
    }
    return false;
}

bool STILparser::shift() {
    if (tokens[i] == "Shift") {
        proc += tokens[i] + " ";
        i++;
        pass("L_BRACKET");
        inst_list();
        pass("R_BRACKET");
        return true;
    }
    return false;
}

bool STILparser::loop() {
    if (tokens[i] == "Loop") {
        i++;
        int_t();
        pass("L_BRACKET");
        inst_list();
        pass("R_BRACKET");
        return true;
    }
    return false;
}

bool STILparser::label() {
    if (id()) {
        if (tokens[i] == ":") {
            i++;
            return true;
        }
        err_exit();
    }
    return false;
}

bool STILparser::inst() {
    label();
    if (loop()) return true;
    if (shift()) return true;
    if (w_inst()) return true;
    if (c_inst()) return true;
    if (f_inst()) return true;
    if (v_inst()) return true;
    if (call_inst()) return true;
    if (macro_inst()) return true;
    if (stop_inst()) return true;
    if (iddq_inst()) return true;
    return false;
}

void STILparser::inst_list() {
    proc = "";
    while (inst() && i < len) {
        if (proc != "") {
            pattern_test.push_back(proc);
        }
        proc = "";
    }
}

//PATTERNS.
bool STILparser::pattern() {
    if (tokens[i] == "Pattern") {
        proc += tokens[i] + " ";
        i++;
        proc += tokens[i] + " ";
        if (!id()) err_exit();
        pass("L_BRACKET");
        inst_list();
        pass("R_BRACKET");
        return true;
    }
    return false;
}

void STILparser::pattern_l() {
    while (pattern() && i < len);
}

//--------------------------------------------------------------

bool STILparser::macro() {
    if (id()) {
        pass("L_BRACKET");
        inst_list();
        pass("R_BRACKET");
        return true;
    }
    return false;
}

bool STILparser::macros() {
    if (tokens[i] == "MacroDefs") {
        i++;
        id();
        pass("L_BRACKET");
        while (macro());
        pass("R_BRACKET");
        return true;
    }
    return false;
}

void STILparser::macros_l() {
    while (macros());
}

bool STILparser::procedure() {
    if (id()) {
        proc += tokens[i - 1] + " ";
        pass("L_BRACKET");
        inst_list();
        pass("R_BRACKET");
        return true;
    }
    return false;
}

bool STILparser::procedures() {
    if (tokens[i] == "Procedures") {
        i++;
        proc += tokens[i] + " ";
        id();
        pass("L_BRACKET");
        while (procedure());
        pass("R_BRACKET");
        return true;
    }
    return false;
}

void STILparser::procedures_l() {
    proc = "";
    while (procedures()) {
        procs.push_back(proc);
        proc = "";
    }
}

bool STILparser::pattern_burst_call() {
    if (tokens[i] == "PatternBurst") {
        i++;
        if (!id()) err_exit();
        return true;
    }
    return false;
}

bool STILparser::pattern_exec() {
    if (tokens[i] == "PatternExec") {
        i++;
        id();
        pass("L_BRACKET");
        while (pattern_burst_call());
        pass("R_BRACKET");
        return true;
    }
    return false;
}

bool STILparser::pattern_exec_l() {
    if (!pattern_exec()) return false;
    while (pattern_exec());
    return true;
}

bool STILparser::pattern_call() {
    if (id()) {
        if (type[i] == "L_BRACKET") {
            i++;
            context();
            pass("R_BRACKET");
        }
        return true;
    }
    return false;
}

bool STILparser::pattern_list() {
    if (tokens[i] == "PatList") {
        i++;
        pass("L_BRACKET");
        while (pattern_call());
        pass("R_BRACKET");
        return true;
    }
    return false;
}

bool STILparser::proced_context() {
    if (tokens[i] == "Procedures") {
        i++;
        if (!id()) err_exit();
        return true;
    }
    return false;
}

bool STILparser::macro_context() {
    if (tokens[i] == "MacroDefs") {
        i++;
        if (!id()) err_exit();
        return true;
    }
    return false;
}

void STILparser::context() {
    macro_context();
    proced_context();
}

bool STILparser::pattern_burst() {
    if (tokens[i] == "PatternBurst") {
        i++;
        if (!id()) err_exit();
        pass("L_BRACKET");
        context();
        pattern_list();
        pass("R_BRACKET");
        return true;
    }
    return false;
}


bool STILparser::pattern_burst_l() {
    if (!pattern_burst()) return false;
    while (pattern_burst());
    return true;
}

//--------------------------------------------------------------

//SCAN STRUCTURES.
void STILparser::scan_clock() {
    if (tokens[i] == "ScanMasterClock") {
        i++;
        if (!id()) err_exit();
        return;
    }
    err_exit();
}

void STILparser::scan_cells() {
    if (tokens[i] == "ScanCells") {
        i++;
        if (type[i] != "STRING") {
            err_exit();
        }
        scan_structure.push_back(tokens[i]);
        while (id()) {
            if (type[i] == "EXCLAMATION") {
                pass("EXCLAMATION");
            }
            if (type[i] == "STRING") {
                scan_structure.push_back(tokens[i]);
            }
        }
        return;
    }
    err_exit();
}

void STILparser::scan_inversion() {
    if (tokens[i] == "ScanInversion") {
        i++;
        if (!int_t()) err_exit();
        return;
    }
    err_exit();
}

void STILparser::scan_out() {
    if (tokens[i] == "ScanOut") {
        i++;
        if (!id()) err_exit();
        return;
    }
    err_exit();
}

void STILparser::scan_in() {
    if (tokens[i] == "ScanIn") {
        i++;
        if (!id()) err_exit();
        return;
    }
    err_exit();
}

void STILparser::scan_length() {
    if (tokens[i] == "ScanLength") {
        i++;
        if (!int_t()) err_exit();
        return;
    }
    err_exit();
}

bool STILparser::scan_chain() {
    if (tokens[i] == "ScanChain") {
        i++;
        if (!id()) err_exit();
        pass("L_BRACKET");
        scan_length();
        scan_in();
        scan_out();
        scan_inversion();
        scan_cells();
        scan_clock();
        pass("R_BRACKET");
        return true;
    }
    return false;
}

bool STILparser::scan_structures() {
    if (tokens[i] == "ScanStructures") {
        i++;
        id();
        pass("L_BRACKET");
        while (scan_chain());
        pass("R_BRACKET");
        return true;
    }
    return false;
}

void STILparser::scan_structures_l() {
    while (scan_structures() && i != len);
}

//--------------------------------------------------------------------------------

bool STILparser::event() {
    if (time_expr()) {
        if (!event_code()) err_exit();
        return true;
    }
    return false;
}

bool STILparser::waveform() {
    string token_name = tokens[i].substr(1,tokens[i].length()-2);
    auto find_it = find(clk_singal.begin(),clk_singal.end(),token_name);
    bool is_clock_singal_wf = find_it != clk_singal.end();
    if (id()) {
        pass("L_BRACKET");
        if (!wfc_seq()) err_exit();
        pass("L_BRACKET");
        if(is_clock_singal_wf){
            if (time_expr()){
                if (type[i] == "CHARS"){
                    if(tokens[i] =="D"){
                        clock_waveform.push_back(make_pair(token_name,0));
                    }else{
                        clock_waveform.push_back(make_pair(token_name,1));
                    }
                    i++;
                }else{
                    err_exit();
                }
            }else{
                err_exit();
            }
        }else if (!event()) err_exit();

        while (event());
        pass("R_BRACKET");
        pass("R_BRACKET");
        return true;
    }
    return false;
}

void STILparser::waveforms() {
    if (tokens[i] == "Waveforms") {
        i++;
        pass("L_BRACKET");
        while (waveform());
        pass("R_BRACKET");
    }
}

bool STILparser::period() {
    if (tokens[i] == "Period") {
        i++;
        if (!time_expr()) err_exit();
        return true;
    }
    return false;
}

bool STILparser::waveform_table() {
    if (tokens[i] == "WaveformTable") {
        i++;
        if (!id()) err_exit();
        pass("L_BRACKET");
        period();
        waveforms();
        pass("R_BRACKET");
        return true;
    }
    return false;
}

bool STILparser::timing() {
    if (tokens[i] == "Timing") {
        i++;
        pass("L_BRACKET");
        while (waveform_table());
        pass("R_BRACKET");
        return true;
    }
    return false;
}

bool STILparser::signal_list(vector<string> *singal_names) {
    if (type[i] == "STRING") {
        while (i < len) {
            if (type[i] == "STRING") {
                if (singal_names != nullptr) {
                    int token_len = tokens[i].length();
//                    cout << tokens[i].substr(1, token_len - 2) << endl;
                    singal_names->push_back(tokens[i].substr(1, token_len - 2));

                }
                i++;
            }
            if (type[i] == "QUOTE") {
                break;
            }
            if (type[i] == "SUM") {
                i++;
                if (type[i] != "STRING")
                    err_exit();
            }


        }
        return true;
    }
    return false;
}

bool STILparser::signal_group() {
    bool is_pi_singal_list = is_pi();
    bool is_po_singal_list = is_po();
    bool is_si_singal_list = tokens[i] == "\"_si\"";
    bool is_so_singal_list = tokens[i] == "\"_so\"";
    bool is_clock_singal_list = tokens[i] == "\"_clk\"";

    if (id()) {
        pass("EQ");
        pass("QUOTE");
        if (is_pi_singal_list) {
            signal_list(&pi_singal);
        } else if (is_po_singal_list) {
            signal_list(&po_singal);
        } else if (is_si_singal_list) {
            signal_list(&si_singal);
        } else if (is_so_singal_list) {
            signal_list(&so_singal);
        } else if(is_clock_singal_list){
            signal_list(&clk_singal);
        }else{
            signal_list(nullptr);
        }

        pass("QUOTE");
        signal_attributes();
        return true;
    }

    return false;
}

bool STILparser::signal_groups() {
    if (tokens[i] == "SignalGroups") {
        i++;
        pass("L_BRACKET");
        while (signal_group());
        pass("R_BRACKET");
        return true;
    }
    return false;
}

bool STILparser::map_rule() {
    if (wfc_seq()) {
        pass("->");
        if (!wfc_seq()) err_exit();
        return true;
    }
    return false;
}

void STILparser::wfc_map() {
    if (tokens[i] == "WFCMap") {
        i++;
        pass("L_BRACKET");
        while (map_rule());
        pass("R_BRACKET");
    }
}

bool STILparser::signal_scan() {
    if (tokens[i] == "ScanIn" || tokens[i] == "ScanOut") {
        i++;
        return true;
    }
    return false;
}

void STILparser::signal_attributes() {
    if (type[i] == "L_BRACKET") {
        i++;
        signal_scan();
        wfc_map();
        pass("R_BRACKET");
    }
}

bool STILparser::signal_dir() {
    if (tokens[i] == "In" || tokens[i] == "Out" || tokens[i] == "InOut" || tokens[i] == "Pseudo") {
        i++;
        return true;
    }
    return false;
}

bool STILparser::signal() {
    if (id()) {
        if (!signal_dir()) err_exit();
        signal_attributes();
        return true;
    }
    return false;
}

bool STILparser::signals() {
    if (tokens[i] == "Signals") {
        i++;
        pass("L_BRACKET");
        while (signal());
        pass("R_BRACKET");
        return true;
    }
    return false;
}

void STILparser::history() {
    if (tokens[i] == "History") {
        i++;
        pass("L_BRACKET");
        pass("R_BRACKET");
    }
}

void STILparser::source() {
    if (tokens[i] == "Source") {
        i++;
        pass("STRING");
    }
}

void STILparser::date() {
    if (tokens[i] == "Date") {
        i++;
        pass("STRING");
    }
}

void STILparser::title() {
    if (tokens[i] == "Title") {
        i++;
        pass("STRING");
    }
}

void STILparser::header() {
    if (tokens[i] == "Header") {
        i++;
        pass("L_BRACKET");
        title();
        date();
        source();
        history();
        pass("R_BRACKET");
    }
}

bool STILparser::design() {
    if (tokens[i] == "Design") {
        i++;
        if (!int_t()) err_exit();
        return true;
    }
    return false;
}

bool STILparser::format() {
    if (tokens[i] == "STIL") {
        i++;
        if (!float_t()) err_exit();
        if (type[i] == "L_BRACKET") {
            i++;
            if (!design()) err_exit();
            pass("R_BRACKET");
        }
        return true;
    }
    return false;
}

void STILparser::program() {
    len = type.size();

    //cout << "format" << endl;
    format();
    //cout << "header" << endl;
    header();
    //cout << "signals" << endl;
    if (!signals()) err_exit();
    //cout << "signal_groups" << endl;
    if (!signal_groups()) err_exit();
    //cout << "timing" << endl;
    if (!timing()) err_exit();
    //cout << "scan_structure" << endl;
    scan_structures_l();
    //cout << "pattern_burst" << endl;
    pattern_burst_l();
    //cout << "pattern_exec" << endl;
    pattern_exec_l();
    //cout << "procedures" << endl;
    procedures_l();
    //cout << "macros" << endl;
    macros_l();
    //cout << "pattern" << endl;
    pattern_l();
}


void STILparser::process_pattern_result(string path_operation) {
    ofstream fout(path_operation);
    for (int i = 1; i < pattern_test.size(); i++) {
        int ptr = 0;
        string temp;
        while (ptr < pattern_test[i].size()) {
            if (pattern_test[i][ptr] == ' ') {
                ++ptr;
                continue;
            }
            temp += pattern_test[i][ptr++];
        }
        ptr = 0;
        while (ptr < temp.size()) {
            if (temp[ptr] == '"') {
                temp[ptr] = ' ';
            }
            ++ptr;
        }
        fout << temp;
        fout << endl;
    }

    fout.close();
}

void STILparser::process_scan_structure(string path_scancell_file) {
    ofstream fout(path_scancell_file);
    for (int i = 0; i < scan_structure.size(); i++) {
        string cell = scan_structure[i];
        int start = 0, end = cell.size() - 1;
        while (cell[start] != '.') start++;
        while (cell[end] != '.') end--;
        cell = cell.substr(start + 1, end - start - 1);
        cell.insert(cell.begin(), '/');
        fout << cell << endl;
    }

    fout.close();
}

void STILparser::parse(string path_external_stil) {
//    cout << "parser start." << endl;
    scan(type, tokens, path_external_stil);

    program();

    string prefix = path_external_stil.substr(0, path_external_stil.rfind(".stil"));
    string path_scancell_file = prefix + ".sc";
    string path_operation = prefix + ".op";

    //for(int i=0;i<scan_structure.size();i++){
    //    cout << scan_structure[i] << endl;
    //}

    process_pattern_result(path_operation);
    process_scan_structure(path_scancell_file);

//    cout << "parser end." << endl;
}

void STILparser::STIL_parser_init() {
    i = 0;
}

bool STILparser::is_pi() {
    if (type[i] == "STRING") {
        if (tokens[i] == "\"_pi\"") {
            return true;
        }
    }
    return false;
}

bool STILparser::is_po() {
    if (type[i] == "STRING") {
        if (tokens[i] == "\"_po\"") {
            return true;
        }
    }
    return false;
}
